package com.sj.purchase.modules.cost.service.stock;

import com.sj.purchase.manager.SkuInfoManager;
import com.sj.purchase.modules.cost.domain.order.Order;
import com.sj.purchase.modules.cost.domain.price.CostPrice;
import com.sj.purchase.modules.cost.repository.order.InOrderItemRepository;
import com.sj.purchase.modules.cost.repository.order.OutOrderItemRepository;
import com.sj.purchase.modules.cost.repository.order.StockAdjustRepository;
import com.sj.purchase.modules.cost.service.price.CostPriceService;
import com.sj.purchase.modules.cost.views.stock.SkuStockReportVO;
import com.sj.purchase.modules.cost.repository.stock.SkuStockRepository;
import com.sj.purchase.modules.cost.domain.WarehouseEnum;
import com.sj.purchase.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Alin on 2017/10/26.
 */
@Service
public class SkuStockReportService {

    @Autowired
    private InOrderItemRepository inOrderItemRepository;

    @Autowired
    private OutOrderItemRepository outOrderItemRepository;

    @Autowired
    private StockAdjustRepository stockAdjustRepository;

    @Autowired
    private SkuInfoManager skuInfoManager;

    @Autowired
    private SkuStockRepository skuStockRepository;

    @Autowired
    private CostPriceService costPriceService;

    private static List<SkuStockReportVO> defaultList = new ArrayList<>(0);

    /**
     * 查询某段时间某个仓库查询 sku：=> （ 期初 入库 出库 期末 ） 的数据
     *
     * @param warehouseEnum
     * @param start
     * @param end
     * @param skuNoList
     * @return SkuStockReportVO
     * @see <a href="https://git.oschina.net/sjxxh/purchase/issues/IF47C">进销库存报表查询接口</a>
     * @see SkuStockReportVO
     */
    public List<SkuStockReportVO> search(WarehouseEnum warehouseEnum, Date start, Date end, List<String> skuNoList) {
        if (skuNoList.isEmpty()) {
            return defaultList;
        }
        //期初
        List<Object[]> l = skuStockRepository.findSkuAndNum(warehouseEnum, start, skuNoList);
        Map<String, Long> beginStockSkuAndNumMap = l.stream().filter(Objects::nonNull).collect(Collectors.toMap(objects -> (String) objects[0], objects -> (Long) objects[1]));
        //入库
        List<Object[]> inOrderSkuAndOrderTypeAndNumList = inOrderItemRepository.findSkuAndOrderTypeAndNum(warehouseEnum, start, end, skuNoList);
        Map<String, Map<Order.OrderType, Long>> inOrderSkuAndOrderTypeAndNumMap = getSkuAndOrderTypeAndNumMap(inOrderSkuAndOrderTypeAndNumList);
        //出库
        List<Object[]> outOrderSkuAndOrderTypeAndNumList = outOrderItemRepository.findSkuAndOrderTypeAndNum(warehouseEnum, start, end, skuNoList);
        Map<String, Map<Order.OrderType, Long>> outOrderSkuAndOrderTypeAndNumMap = getSkuAndOrderTypeAndNumMap(outOrderSkuAndOrderTypeAndNumList);
        //库存调整
        Map<String, Long> adjustStockSkuAndNumMap = stockAdjustRepository.findSkuAndNum(warehouseEnum, start, end, skuNoList).stream().collect(Collectors.toMap(objects -> (String) objects[0], objects -> (Long) objects[1]));
        String dateSegment = SkuStockReportVO.getDateSegment(start, end);
        //移動成本價
        Map<String, List<CostPrice>> skuCostPriceCache = costPriceService.getSkuCostPriceCache(costPriceService.listCostPrice(DateUtils.addDays(start, -10), end));
        List<SkuStockReportVO> list = skuNoList.stream().map(skuNo -> new SkuStockReportVO().setSkuNO(skuNo).setSkuName(skuInfoManager.getSkuInfo(skuNo).getSkuname()).setDateSegment(dateSegment).
                setBeginStock(beginStockSkuAndNumMap.getOrDefault(skuNo, 0L)).
                setInPurchaseStock(searchSkuStock(inOrderSkuAndOrderTypeAndNumMap, skuNo, Order.OrderType.IN_PURCHASE)).setInReturnStock(searchSkuStock(inOrderSkuAndOrderTypeAndNumMap, skuNo, Order.OrderType.IN_RETURN)).
                setOutOtherStock(searchSkuStock(outOrderSkuAndOrderTypeAndNumMap, skuNo, Order.OrderType.OUT_OTHER)).setOutProcurementReturns(searchSkuStock(outOrderSkuAndOrderTypeAndNumMap, skuNo, Order.OrderType.OUT_PROCUREMENT_RETURNS)).setOutSalesStock(searchSkuStock(outOrderSkuAndOrderTypeAndNumMap, skuNo, Order.OrderType.OUT_SALES)).
                setAdjustStock(adjustStockSkuAndNumMap.getOrDefault(skuNo, 0L)).
                calculatorEndStock().//计算期末
                endStockCost(costPriceService.getCostPrice(skuCostPriceCache, skuNo, end))      //计算期末成本
        ).collect(Collectors.toList());
        return list;
    }


    /**
     * 将数组转换为map方便查询
     *
     * @param skuAndOrderTypeAndNumList
     * @return 二维的一个map
     */
    private Map<String, Map<Order.OrderType, Long>> getSkuAndOrderTypeAndNumMap(List<Object[]> skuAndOrderTypeAndNumList) {
        return skuAndOrderTypeAndNumList.stream().collect(() -> new HashMap<String, Map<Order.OrderType, Long>>(), (map, skuAndOrderTypeAndNum) -> {
            String sku = (String) skuAndOrderTypeAndNum[0];
            Order.OrderType orderType = (Order.OrderType) skuAndOrderTypeAndNum[1];
            Long num = (Long) skuAndOrderTypeAndNum[2];
            if (!map.containsKey(sku)) {
                map.put(sku, new HashMap<>());
            }
            map.get(sku).put(orderType, num);
        }, Map::putAll);
    }

    /**
     * 查詢某個sku某個訂單類型的sku庫存數量
     *
     * @param skuAndOrderTypeAndNumMap
     * @param sku
     * @param orderType
     * @return 庫存數量
     */
    private Long searchSkuStock(Map<String, Map<Order.OrderType, Long>> skuAndOrderTypeAndNumMap, String sku, Order.OrderType orderType) {
        return skuAndOrderTypeAndNumMap.containsKey(sku) ? skuAndOrderTypeAndNumMap.get(sku).getOrDefault(orderType, 0L) : 0L;
    }


}
